//! 日志宏测试
//!
//! 测试 FR2: 用户可通过宏记录日志：trace!、debug!、info!、warn!、error!、fatal!
//! 测试 FR3: 日志记录包含时间戳、级别、模块路径、消息内容
//! 测试 FR4: 用户可指定日志的 target 模块
//! 测试 FR5: 系统支持格式化参数

mod common;

#[allow(unused_imports)]
use common::MockAppender;
use serial_test::serial;

// ============================================================================
// P0 测试：宏存在性和基本调用
// ============================================================================

/// [P0] 测试 trace! 宏存在且可调用
#[test]
#[serial]
fn test_trace_macro() {
    // GIVEN: log4r 宏已导出
    // WHEN: 调用 trace! 宏
    // THEN: 应编译通过且不 panic

    log4r::trace!("trace message");
    log4r::trace!("trace with arg: {}", 42);
}

/// [P0] 测试 debug! 宏存在且可调用
#[test]
#[serial]
fn test_debug_macro() {
    // GIVEN: log4r 宏已导出
    // WHEN: 调用 debug! 宏
    // THEN: 应编译通过且不 panic

    log4r::debug!("debug message");
    log4r::debug!("debug with arg: {}", "test");
}

/// [P0] 测试 info! 宏存在且可调用
#[test]
#[serial]
fn test_info_macro() {
    // GIVEN: log4r 宏已导出
    // WHEN: 调用 info! 宏
    // THEN: 应编译通过且不 panic

    log4r::info!("info message");
    log4r::info!("info with arg: {}", 1.5);
}

/// [P0] 测试 warn! 宏存在且可调用
#[test]
#[serial]
fn test_warn_macro() {
    // GIVEN: log4r 宏已导出
    // WHEN: 调用 warn! 宏
    // THEN: 应编译通过且不 panic

    log4r::warn!("warn message");
    log4r::warn!("warn with arg: {}", true);
}

/// [P0] 测试 error! 宏存在且可调用
#[test]
#[serial]
fn test_error_macro() {
    // GIVEN: log4r 宏已导出
    // WHEN: 调用 error! 宏
    // THEN: 应编译通过且不 panic

    log4r::error!("error message");
    log4r::error!("error with arg: {:?}", vec![1, 2, 3]);
}

/// [P0] 测试 fatal! 宏存在且可调用
#[test]
#[serial]
fn test_fatal_macro() {
    // GIVEN: log4r 宏已导出
    // WHEN: 调用 fatal! 宏
    // THEN: 应编译通过且不 panic
    // NOTE: fatal! 内部添加 fatal=true 字段标记

    log4r::fatal!("fatal message");
    log4r::fatal!("fatal with arg: {}", "critical");
}

// ============================================================================
// P1 测试：格式化参数和 target 支持
// ============================================================================

/// [P1] 测试带格式化参数的日志 (FR5)
#[test]
#[serial]
fn test_macro_with_format_args() {
    // GIVEN: log4r 宏已导出
    // WHEN: 调用带格式化参数的宏
    // THEN: 应编译通过且不 panic

    let value = 42;
    let name = "test";

    // 位置参数
    log4r::info!("value={}, name={}", value, name);

    // 命名参数
    log4r::info!("value={value}, name={name}");

    // 多种类型
    log4r::debug!("int={}, float={}, bool={}", 1, 2.5, true);
}

/// [P1] 测试带 target 的日志 (FR4)
#[test]
#[serial]
fn test_macro_with_target() {
    // GIVEN: log4r 宏已导出
    // WHEN: 调用带 target 参数的宏
    // THEN: 应编译通过且不 panic

    log4r::trace!(target: "custom_module", "targeted trace");
    log4r::debug!(target: "custom_module", "targeted debug");
    log4r::info!(target: "custom_module", "targeted info");
    log4r::warn!(target: "custom_module", "targeted warn");
    log4r::error!(target: "custom_module", "targeted error");
    log4r::fatal!(target: "custom_module", "targeted fatal");
}

/// [P1] 测试 target 和格式化参数组合
#[test]
#[serial]
fn test_macro_with_target_and_args() {
    // GIVEN: log4r 宏已导出
    // WHEN: 调用带 target 和格式化参数的宏
    // THEN: 应编译通过且不 panic

    let id = 123;
    log4r::info!(target: "my_app::db", "query id={}", id);
    log4r::warn!(target: "my_app::http", "slow response: {}ms", 500);
}

// ============================================================================
// P1 测试：日志内容验证（需要初始化系统后启用）
// ============================================================================

/// [P1] 测试日志包含时间戳 (FR3)
#[test]
#[serial]
fn test_log_contains_timestamp() {
    // GIVEN: 日志系统已初始化
    // WHEN: 记录日志
    // THEN: 日志事件应包含时间戳

    // let appender = MockAppender::new();
    // log4r::builder()
    //     .with_appender(appender.clone())
    //     .init()
    //     .unwrap();
    //
    // log4r::info!("test message");
    //
    // let event = appender.last_event().unwrap();
    // assert!(!event.timestamp.is_empty());
}

/// [P1] 测试日志包含模块路径 (FR3)
#[test]
#[serial]
fn test_log_contains_module_path() {
    // GIVEN: 日志系统已初始化
    // WHEN: 记录日志
    // THEN: 日志事件应包含模块路径

    // let appender = MockAppender::new();
    // log4r::builder()
    //     .with_appender(appender.clone())
    //     .init()
    //     .unwrap();
    //
    // log4r::info!("test message");
    //
    // let event = appender.last_event().unwrap();
    // assert!(event.target.contains("macros_test"));
}

// ============================================================================
// P2 测试：级别过滤（需要初始化系统后启用）
// ============================================================================

/// [P2] 测试级别过滤：低于设定级别的日志不记录
#[test]
#[serial]
fn test_level_filtering_in_macros() {
    // GIVEN: 日志级别设为 WARN
    // WHEN: 调用各级别宏
    // THEN: TRACE/DEBUG/INFO 不应记录

    // let appender = MockAppender::new();
    // log4r::builder()
    //     .with_level(log4r::Level::Warn)
    //     .with_appender(appender.clone())
    //     .init()
    //     .unwrap();
    //
    // log4r::trace!("trace");
    // log4r::debug!("debug");
    // log4r::info!("info");
    // log4r::warn!("warn");
    // log4r::error!("error");
    //
    // assert_eq!(appender.count_level("TRACE"), 0);
    // assert_eq!(appender.count_level("DEBUG"), 0);
    // assert_eq!(appender.count_level("INFO"), 0);
    // assert_eq!(appender.count_level("WARN"), 1);
    // assert_eq!(appender.count_level("ERROR"), 1);
}

// ============================================================================
// P1 测试：延迟格式化 (AC-2.4.4)
// ============================================================================

/// [P1] 测试延迟格式化：被过滤的日志不执行格式化 (AC-2.4.4)
///
/// tracing 宏天然支持延迟格式化，当日志级别被过滤时，
/// 格式化参数不会被求值。此测试验证这一行为。
#[test]
#[serial]
fn test_lazy_formatting() {
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::sync::Arc;
    use tracing::field::{Field, Visit};
    use tracing::{Event, Subscriber};
    use tracing_subscriber::layer::SubscriberExt;
    use tracing_subscriber::registry::LookupSpan;

    // GIVEN: 一个计数器用于跟踪格式化调用次数
    let format_count = Arc::new(AtomicUsize::new(0));
    let format_count_clone = format_count.clone();

    struct CountingVisitor(Arc<AtomicUsize>);

    impl Visit for CountingVisitor {
        fn record_debug(&mut self, field: &Field, _value: &dyn std::fmt::Debug) {
            // 当 tracing 记录字段时，说明格式化被执行了
            if field.name() == "message" {
                self.0.fetch_add(1, Ordering::SeqCst);
            }
        }
    }

    struct CountingLayer(Arc<AtomicUsize>);

    impl<S> tracing_subscriber::Layer<S> for CountingLayer
    where
        S: Subscriber + for<'a> LookupSpan<'a>,
    {
        fn on_event(&self, event: &Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>) {
            let mut visitor = CountingVisitor(self.0.clone());
            event.record(&mut visitor);
        }
    }

    // WHEN: 设置一个只接受 ERROR 级别的 subscriber
    let subscriber = tracing_subscriber::registry()
        .with(tracing_subscriber::filter::LevelFilter::ERROR)
        .with(CountingLayer(format_count_clone));

    // 使用 with_default 临时设置 subscriber
    tracing::subscriber::with_default(subscriber, || {
        // 调用 DEBUG 级别宏（应被过滤，不执行格式化）
        log4r::debug!("debug message");

        // 调用 ERROR 级别宏（应执行格式化）
        log4r::error!("error message");
    });

    // THEN: 只有 ERROR 级别的日志被记录
    let count = format_count.load(Ordering::SeqCst);
    assert_eq!(count, 1, "只有 ERROR 级别应被记录，实际记录 {} 条", count);
}

/// [P1] 测试延迟格式化：多级别过滤验证 (AC-2.4.4)
#[test]
#[serial]
fn test_lazy_formatting_multiple_levels() {
    use std::sync::atomic::{AtomicUsize, Ordering};
    use std::sync::Arc;
    use tracing::field::{Field, Visit};
    use tracing::{Event, Subscriber};
    use tracing_subscriber::layer::SubscriberExt;
    use tracing_subscriber::registry::LookupSpan;

    // GIVEN: 一个计数器用于跟踪日志记录次数
    let log_count = Arc::new(AtomicUsize::new(0));
    let log_count_clone = log_count.clone();

    struct CountingVisitor(Arc<AtomicUsize>);

    impl Visit for CountingVisitor {
        fn record_debug(&mut self, field: &Field, _value: &dyn std::fmt::Debug) {
            if field.name() == "message" {
                self.0.fetch_add(1, Ordering::SeqCst);
            }
        }
    }

    struct CountingLayer(Arc<AtomicUsize>);

    impl<S> tracing_subscriber::Layer<S> for CountingLayer
    where
        S: Subscriber + for<'a> LookupSpan<'a>,
    {
        fn on_event(&self, event: &Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>) {
            let mut visitor = CountingVisitor(self.0.clone());
            event.record(&mut visitor);
        }
    }

    // WHEN: 设置一个只接受 WARN 及以上级别的 subscriber
    let subscriber = tracing_subscriber::registry()
        .with(tracing_subscriber::filter::LevelFilter::WARN)
        .with(CountingLayer(log_count_clone));

    tracing::subscriber::with_default(subscriber, || {
        // 这些应被过滤
        log4r::trace!("trace message");
        log4r::debug!("debug message");
        log4r::info!("info message");

        // 这些应被记录
        log4r::warn!("warn message");
        log4r::error!("error message");
        log4r::fatal!("fatal message"); // fatal 映射到 error 级别
    });

    // THEN: 只有 WARN/ERROR/FATAL 级别的日志被记录（3 条）
    let count = log_count.load(Ordering::SeqCst);
    assert_eq!(
        count, 3,
        "应记录 3 条日志（WARN/ERROR/FATAL），实际记录 {} 条",
        count
    );
}

/// [P1] 测试延迟格式化：验证昂贵计算不被执行 (AC-2.4.4)
///
/// 此测试验证当日志级别被过滤时，格式化参数中的表达式不会被求值。
#[test]
#[serial]
fn test_lazy_formatting_expensive_computation() {
    use std::sync::atomic::{AtomicUsize, Ordering};
    use tracing_subscriber::layer::SubscriberExt;

    // GIVEN: 一个计数器用于跟踪昂贵计算的调用次数
    static COMPUTATION_COUNT: AtomicUsize = AtomicUsize::new(0);

    fn expensive_computation() -> &'static str {
        COMPUTATION_COUNT.fetch_add(1, Ordering::SeqCst);
        "computed"
    }

    // 重置计数器
    COMPUTATION_COUNT.store(0, Ordering::SeqCst);

    // WHEN: 设置一个只接受 ERROR 级别的 subscriber（无 Layer，只有过滤器）
    let subscriber =
        tracing_subscriber::registry().with(tracing_subscriber::filter::LevelFilter::ERROR);

    tracing::subscriber::with_default(subscriber, || {
        // DEBUG 级别被过滤，expensive_computation() 不应被调用
        log4r::debug!("result: {}", expensive_computation());

        // ERROR 级别通过，expensive_computation() 应被调用
        log4r::error!("result: {}", expensive_computation());
    });

    // THEN: 昂贵计算只应被调用一次（ERROR 级别）
    let count = COMPUTATION_COUNT.load(Ordering::SeqCst);
    assert_eq!(
        count, 1,
        "昂贵计算应只被调用 1 次（ERROR），实际调用 {} 次",
        count
    );
}

// ============================================================================
// P1 测试：fatal! 宏的 fatal=true 字段标记 (AC-2.4.5)
// ============================================================================

/// [P1] 测试 fatal! 宏添加 fatal=true 字段标记 (AC-2.4.5)
///
/// fatal! 宏应在 tracing event 中添加 fatal=true 字段，
/// 以便后续 Layer 识别并触发系统日志写入。
#[test]
#[serial]
fn test_fatal_macro_adds_fatal_field() {
    use std::sync::atomic::{AtomicBool, Ordering};
    use tracing::field::{Field, Visit};
    use tracing::{Event, Subscriber};
    use tracing_subscriber::layer::SubscriberExt;
    use tracing_subscriber::registry::LookupSpan;

    // GIVEN: 一个自定义 Layer 用于捕获 fatal 字段
    static FATAL_FIELD_FOUND: AtomicBool = AtomicBool::new(false);
    static FATAL_FIELD_VALUE: AtomicBool = AtomicBool::new(false);

    struct FatalFieldVisitor;

    impl Visit for FatalFieldVisitor {
        fn record_bool(&mut self, field: &Field, value: bool) {
            if field.name() == "fatal" {
                FATAL_FIELD_FOUND.store(true, Ordering::SeqCst);
                FATAL_FIELD_VALUE.store(value, Ordering::SeqCst);
            }
        }

        fn record_debug(&mut self, _field: &Field, _value: &dyn std::fmt::Debug) {}
    }

    struct FatalDetectorLayer;

    impl<S> tracing_subscriber::Layer<S> for FatalDetectorLayer
    where
        S: Subscriber + for<'a> LookupSpan<'a>,
    {
        fn on_event(&self, event: &Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>) {
            let mut visitor = FatalFieldVisitor;
            event.record(&mut visitor);
        }
    }

    // 重置状态
    FATAL_FIELD_FOUND.store(false, Ordering::SeqCst);
    FATAL_FIELD_VALUE.store(false, Ordering::SeqCst);

    // WHEN: 设置带有 FatalDetectorLayer 的 subscriber 并调用 fatal! 宏
    let subscriber = tracing_subscriber::registry().with(FatalDetectorLayer);

    tracing::subscriber::with_default(subscriber, || {
        log4r::fatal!("致命错误测试");
    });

    // THEN: 应检测到 fatal=true 字段
    assert!(
        FATAL_FIELD_FOUND.load(Ordering::SeqCst),
        "fatal! 宏应添加 fatal 字段"
    );
    assert!(
        FATAL_FIELD_VALUE.load(Ordering::SeqCst),
        "fatal 字段值应为 true"
    );
}

/// [P1] 测试 error! 宏不添加 fatal 字段 (AC-2.4.5 对比测试)
#[test]
#[serial]
fn test_error_macro_no_fatal_field() {
    use std::sync::atomic::{AtomicBool, Ordering};
    use tracing::field::{Field, Visit};
    use tracing::{Event, Subscriber};
    use tracing_subscriber::layer::SubscriberExt;
    use tracing_subscriber::registry::LookupSpan;

    // GIVEN: 一个自定义 Layer 用于检测 fatal 字段
    static FATAL_FIELD_FOUND: AtomicBool = AtomicBool::new(false);

    struct FatalFieldVisitor;

    impl Visit for FatalFieldVisitor {
        fn record_bool(&mut self, field: &Field, _value: bool) {
            if field.name() == "fatal" {
                FATAL_FIELD_FOUND.store(true, Ordering::SeqCst);
            }
        }

        fn record_debug(&mut self, _field: &Field, _value: &dyn std::fmt::Debug) {}
    }

    struct FatalDetectorLayer;

    impl<S> tracing_subscriber::Layer<S> for FatalDetectorLayer
    where
        S: Subscriber + for<'a> LookupSpan<'a>,
    {
        fn on_event(&self, event: &Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>) {
            let mut visitor = FatalFieldVisitor;
            event.record(&mut visitor);
        }
    }

    // 重置状态
    FATAL_FIELD_FOUND.store(false, Ordering::SeqCst);

    // WHEN: 设置带有 FatalDetectorLayer 的 subscriber 并调用 error! 宏
    let subscriber = tracing_subscriber::registry().with(FatalDetectorLayer);

    tracing::subscriber::with_default(subscriber, || {
        log4r::error!("普通错误测试");
    });

    // THEN: 不应检测到 fatal 字段
    assert!(
        !FATAL_FIELD_FOUND.load(Ordering::SeqCst),
        "error! 宏不应添加 fatal 字段"
    );
}

/// [P1] 测试 fatal! 宏带 target 参数时也添加 fatal=true 字段 (AC-2.4.5)
#[test]
#[serial]
fn test_fatal_macro_with_target_adds_fatal_field() {
    use std::sync::atomic::{AtomicBool, Ordering};
    use tracing::field::{Field, Visit};
    use tracing::{Event, Subscriber};
    use tracing_subscriber::layer::SubscriberExt;
    use tracing_subscriber::registry::LookupSpan;

    static FATAL_FIELD_FOUND: AtomicBool = AtomicBool::new(false);
    static FATAL_FIELD_VALUE: AtomicBool = AtomicBool::new(false);

    struct FatalFieldVisitor;

    impl Visit for FatalFieldVisitor {
        fn record_bool(&mut self, field: &Field, value: bool) {
            if field.name() == "fatal" {
                FATAL_FIELD_FOUND.store(true, Ordering::SeqCst);
                FATAL_FIELD_VALUE.store(value, Ordering::SeqCst);
            }
        }

        fn record_debug(&mut self, _field: &Field, _value: &dyn std::fmt::Debug) {}
    }

    struct FatalDetectorLayer;

    impl<S> tracing_subscriber::Layer<S> for FatalDetectorLayer
    where
        S: Subscriber + for<'a> LookupSpan<'a>,
    {
        fn on_event(&self, event: &Event<'_>, _ctx: tracing_subscriber::layer::Context<'_, S>) {
            let mut visitor = FatalFieldVisitor;
            event.record(&mut visitor);
        }
    }

    // 重置状态
    FATAL_FIELD_FOUND.store(false, Ordering::SeqCst);
    FATAL_FIELD_VALUE.store(false, Ordering::SeqCst);

    // WHEN: 调用带 target 的 fatal! 宏
    let subscriber = tracing_subscriber::registry().with(FatalDetectorLayer);

    tracing::subscriber::with_default(subscriber, || {
        log4r::fatal!(target: "my_app::core", "带 target 的致命错误");
    });

    // THEN: 应检测到 fatal=true 字段
    assert!(
        FATAL_FIELD_FOUND.load(Ordering::SeqCst),
        "带 target 的 fatal! 宏应添加 fatal 字段"
    );
    assert!(
        FATAL_FIELD_VALUE.load(Ordering::SeqCst),
        "fatal 字段值应为 true"
    );
}
